package ir

import (
	"fmt"

	"gitee.com/u-language/u-language/ucom/ast"
	"gitee.com/u-language/u-language/ucom/enum"
)

const (
	noimm = iota
	intTyp
	floatTyp
)

// ToState 转换状态
//
// 记录某次ast转换ir的特定状态，并发不安全
type ToState struct {
	table map[string]string
	auto  *autoVar
}

// NewToState 返回一个可使用的 [ToState] 指针
func NewToState() *ToState {
	return &ToState{
		table: make(map[string]string),
		auto:  newautoVar(),
	}
}

// ToASSIGN 将一个赋值节点转换为中间代码
func (t *ToState) ToASSIGN(ptr *ast.ASSIGNNode, sbt *ast.Sbt) (ret []IrNode) {
	ret = make([]IrNode, 0, 1)
	var ptrir IrNode
	ptrir.Op = MOVOP                                                              //操作为赋值
	ptrir.Arg1Obj, ptrir.Arg1Typ = t.ToExprNode(ptr.Src, sbt, &ret)               //将源操作数转换为中间代码
	ptrir.ResultObj, ptrir.ResultTyp = t.ObjectToArg(ptr.Dest.(*ast.Object), sbt) //设置赋值目的操作数
	if ptrir.ResultTyp.IsImm() {                                                  //如果目的是立即数
		panic(fmt.Errorf("无法给立即数赋值 %+v", ptr))
	}
	ret = append(ret, ptrir)
	t.ASSIGNOptimize(&ptrir, &ret)
	return ret
}

// ToAmexpr 将一个算术表达式节点转换为中间代码
func (t *ToState) ToAmexpr(ptr *ast.OpExpr, sbt *ast.Sbt) (ret []IrNode) {
	ret = make([]IrNode, 0, 1)
	var (
		ptrir IrNode
		typ   int8
	)
	switch ptr.OP { //设置运算类型
	case enum.ADDOP:
		ptrir.Op = ADDOP
	case enum.SUBOP:
		ptrir.Op = SUBOP
	}
	ptrir.Arg1Obj, ptrir.Arg1Typ = t.ToExprNode(ptr.Src1, sbt, &ret)
	switch n := ptr.Src2.(type) { //转换右边的源操作数
	case *ast.Object:
		switch n.Kind {
		case ast.INTOBJ: //是int型立即数
			typ = intTyp
		case ast.FLOATOBJ: //是float型立即数
			typ = floatTyp
		case ast.SymbolObj: //是变量
			info := sbt.Have(n.Name)
			switch info.Type() {
			case "int": //是int型变量
				typ = intTyp
			case "float": //是float型变量
				typ = floatTyp
			}
		}
		ptrir.Arg2Obj, ptrir.Arg2Typ = t.ObjectToArg(n, sbt)
	case *ast.OpExpr: //是运算表达式节点
		ret = append(ret, t.ToAmexpr(n, sbt)...)              //转换为中间代码
		ptrir.Arg2Obj, ptrir.Arg2Typ = t.AmexprOptimize(&ret) //执行优化
	}
	bol := t.AmexprOptimizeOrImm(&ptrir, typ, ptr.OP)
	if bol {
		return append(ret, ptrir)
	}
	switch typ {
	case intTyp:
		ptrir.ResultObj, ptrir.ResultTyp = t.auto.Get(), Tmp
	case floatTyp:
		ptrir.ResultObj, ptrir.ResultTyp = t.auto.Get(), Tmp
	}
	return append(ret, ptrir)
}

// ToExprNode 转换一个表达式节点
func (t *ToState) ToExprNode(ptr ast.Node, sbt *ast.Sbt, ret *[]IrNode) (ArgObj string, ArgTyp ArgEnum) {
	switch n := ptr.(type) {
	case *ast.Object: //是一个对象
		ArgObj, ArgTyp = t.ObjectToArg(n, sbt)
	case *ast.OpExpr: //是运算表达式节点
		(*ret) = append((*ret), t.ToAmexpr(n, sbt)...)
		ArgObj, ArgTyp = t.AmexprOptimize(ret)
	}
	return
}

// ObjectToArg 转换一个对象为中间代码操作数
func (t *ToState) ObjectToArg(obj *ast.Object, sbt *ast.Sbt) (ArgObj string, ArgTyp ArgEnum) {
	switch obj.Kind {
	case ast.SymbolObj: //是变量
		ArgObj = obj.Name
		info := sbt.Have(obj.Name)
		var IsStackAlloc bool
		if v, ok := info.Info.(*ast.VarNode); ok {
			IsStackAlloc = v.IsFunc
		} else {
			IsStackAlloc = info.Info.(ast.VarInfoSbt).IsStackAlloc
		}
		if IsStackAlloc { //是栈上变量
			ArgTyp = StackVar
		} else { //是全局变量
			ArgTyp = Var
		}
	case ast.INTOBJ: //是int型立即数
		ArgObj = obj.Name
		ArgTyp = ImmInt
	case ast.FLOATOBJ: //是float型立即数
		ArgObj = obj.Name
		ArgTyp = ImmFloat
	}
	return
}

// HavaTmpVar 查找本次转换是否存在临时变量
//
//   - name是被查找的临时变量
//
// 如果查找到存在，返回临时变量的值
//
// 如果查找到不存在，将 panic
func (t *ToState) HavaTmpVar(name string) string {
	v, ok := t.table[name]
	if ok {
		return v
	}
	panic(fmt.Errorf("不存在的临时变量 %+v", name))
}
